home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Dr. Windows 3
/
dr win3.zip
/
dr win3
/
PROGRAMR
/
OLE2BOOK.ZIP
/
CHAP13.ZIP
/
PATRON
/
IDROPTGT.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-27
|
15KB
|
576 lines
/*
* IDROPTGT.CPP
*
* Implementation of a DropTarget object for Patron,
*
* Copyright (c)1993 Microsoft Corporation, All Rights Reserved
*
* Kraig Brockschmidt, Software Design Engineer
* Microsoft Systems Developer Relations
*
* Internet : kraigb@microsoft.com
* Compuserve: >INTERNET:kraigb@microsoft.com
*/
#include "patron.h"
/*
* CDropTarget::CDropTarget
* CDropTarget::~CDropTarget
*
* Constructor Parameters:
* pDoc LPCPatronDoc of the window containing us.
*/
CDropTarget::CDropTarget(LPCPatronDoc pDoc)
{
m_cRef=0;
m_pDoc=pDoc;
m_pIDataObject=NULL;
return;
}
CDropTarget::~CDropTarget(void)
{
return;
}
/*
* CDropTarget::QueryInterface
* CDropTarget::AddRef
* CDropTarget::Release
*
* Purpose:
* IUnknown members for CDropTarget object.
*/
STDMETHODIMP CDropTarget::QueryInterface(REFIID riid, LPVOID FAR *ppv)
{
*ppv=NULL;
//Any interface on this object is the object pointer.
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDropTarget))
*ppv=(LPVOID)this;
/*
* If we actually assign an interface to ppv we need to AddRef it
* since we're returning a new pointer.
*/
if (NULL!=*ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG) CDropTarget::AddRef(void)
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CDropTarget::Release(void)
{
ULONG cRefT;
cRefT=--m_cRef;
if (0L==m_cRef)
delete this;
return cRefT;
}
/*
* CDropTarget::DragEnter
*
* Purpose:
* Indicates that data in a drag operation has been dragged over our
* window that's a potential target. We are to decide if it's something
* we're interested in or not.
*
* Parameters:
* pIDataSource LPDATAOBJECT providing the source data.
* grfKeyState DWORD flags indicating states of keys and mouse buttons.
* pt POINTL coordinates in the client space of the document.
* pdwEffect LPDWORD into which we'll place the appropriate effect
* flag for this point.
*
* Return Value:
* SCODE NOERROR
*/
STDMETHODIMP CDropTarget::DragEnter(LPDATAOBJECT pIDataSource
, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
{
LPCPages ppg=m_pDoc->m_pPG;
HWND hWnd;
FORMATETC fe;
STGMEDIUM stm;
UINT uRet;
m_fFeedback=FALSE;
m_pIDataObject=NULL;
if (!m_pDoc->FQueryPasteFromData(pIDataSource, &fe, NULL))
{
*pdwEffect=DROPEFFECT_NONE;
return NOERROR;
}
//Check if we can link from this data object as well.
ppg->m_fLinkAllowed=SUCCEEDED(OleQueryLinkFromData(pIDataSource));
//We never allow it dragging in ourselves.
ppg->m_fLinkAllowed &= !ppg->m_fDragSource;
//Check if this is a valid drop point.
uRet=ppg->UTestDroppablePoint(&pt);
ppg->m_uLastTest=uRet;
if (UDROP_NONE==uRet)
*pdwEffect=DROPEFFECT_NONE;
else
{
//Default is move if we can, in fact drop here.
*pdwEffect=DROPEFFECT_MOVE;
if (grfKeyState & MK_CONTROL)
{
if (ppg->m_fLinkAllowed && (grfKeyState & MK_SHIFT))
*pdwEffect=DROPEFFECT_LINK;
else
*pdwEffect=DROPEFFECT_COPY;
}
}
m_pIDataObject=pIDataSource;
m_pIDataObject->AddRef();
/*
* Determine the size of the data, if we can. The default is
* a small rectangle since we can't easily tell what size something
* will be if we're pulling in a metafile or bitmap. It's not
* a good idea to render it here with ::GetData just to find that out.
* We only know the size if it's our own object in which case a
* ::GetData will be fast.
*/
if (fe.cfFormat==m_pDoc->m_cf)
{
if (SUCCEEDED(pIDataSource->GetData(&fe, &stm)))
{
LPPATRONOBJECT ppo;
RECT rc;
ppo=(LPPATRONOBJECT)GlobalLock(stm.hGlobal);
SetRect(&rc, (int)ppo->szl.cx, -(int)ppo->szl.cy, 0, 0);
RectConvertMappings(&rc, NULL, TRUE);
SETSIZEL(m_szl, rc.left, rc.top);
m_ptPick=ppo->ptlPick;
m_fe=ppo->fe;
GlobalUnlock(stm.hGlobal);
ReleaseStgMedium(&stm);
}
}
else
{
SETSIZEL(m_szl, 30, 30);
m_ptPick.x=0;
m_ptPick.y=0;
m_fe.cfFormat=0;
/*
* Try to get CF_OBJECTDESCRIPTOR which might have a size and
* a pick point. If it exists, then always use the point but
* still default to a 30*30 size if the sizes are zero.
*/
uRet=RegisterClipboardFormat(CF_OBJECTDESCRIPTOR);
SETDefFormatEtc(fe, uRet, TYMED_HGLOBAL);
if (SUCCEEDED(pIDataSource->GetData(&fe, &stm)))
{
LPOBJECTDESCRIPTOR pOD;
pOD=(LPOBJECTDESCRIPTOR)GlobalLock(stm.hGlobal);
//Get the size, converting to LOMETRIC.
if (0!=pOD->sizel.cx && 0!=pOD->sizel.cy)
XformSizeInHimetricToPixels(NULL, &pOD->sizel, &m_szl);
//POINTL and SIZEL are interchangeable
XformSizeInHimetricToPixels(NULL, (LPSIZEL)&pOD->pointl
, (LPSIZEL)&m_ptPick);
GlobalUnlock(stm.hGlobal);
ReleaseStgMedium(&stm);
}
}
//Bring the document window up front and show what a drop will do.
hWnd=m_pDoc->Window();
BringWindowToTop(hWnd);
UpdateWindow(hWnd);
ppg->m_uVScrollCode=0xFFFF;
ppg->m_uHScrollCode=0xFFFF;
m_fPendingRepaint=FALSE;
pt.x-=m_ptPick.x;
pt.y-=m_ptPick.y;
m_ptLast=pt;
m_fFeedback=TRUE;
ppg->DrawDropTargetRect(&pt, &m_szl);
return NOERROR;
}
/*
* CDropTarget::DragOver
*
* Purpose:
* Indicates that the mouse was moved inside the window represented
* by this drop target. This happens on every WM_MOUSEMOVE, so this
* function should be very efficient.
*
* Parameters:
* grfKeyState DWORD providing the current keyboard and mouse states
* pt POINTL where the mouse currently is.
* pdwEffect LPDWORD in which to store the effect flag for this point.
*
* Return Value:
* SCODE NOERROR
*/
STDMETHODIMP CDropTarget::DragOver(DWORD grfKeyState, POINTL pt
, LPDWORD pdwEffect)
{
LPCPages ppg=m_pDoc->m_pPG;
UINT uRet, uLast;
UINT xPos, yPos;
if (NULL==m_pIDataObject)
return NOERROR;
//Check if this is still a valid point. uRet is used below as well.
uRet=ppg->UTestDroppablePoint(&pt);
if (UDROP_NONE==uRet)
*pdwEffect=DROPEFFECT_NONE;
else
{
//Store these before possibly ORing in DROPEFFECT_SCROLL
*pdwEffect=DROPEFFECT_MOVE;
if (grfKeyState & MK_CONTROL)
{
if (ppg->m_fLinkAllowed && (grfKeyState & MK_SHIFT))
*pdwEffect=DROPEFFECT_LINK;
else
*pdwEffect=DROPEFFECT_COPY;
}
}
//If we haven't moved and we are not scrolling, then we're done.
if ((pt.x-m_ptPick.x==m_ptLast.x) && (pt.y-m_ptPick.y==m_ptLast.y)
&& !((UDROP_INSETHORZ | UDROP_INSETVERT) & ppg->m_uLastTest))
{
return NOERROR;
}
//Remove the last feedback rectangle.
if (m_fFeedback)
ppg->DrawDropTargetRect(&m_ptLast, &m_szl);
uLast=ppg->m_uLastTest;
ppg->m_uLastTest=uRet;
if (UDROP_NONE==uRet)
{
//If we are now an invalid point, better repaint as necessary
if (m_fPendingRepaint)
{
UpdateWindow(ppg->m_hWnd);